在我們的前幾篇文章中,我們已經介紹了如何使用表單來捕獲用戶輸入數據,並通過 EmailJS 發送表單數據。今天,我們將深入探討如何利用 sessionStorage
來實現數據持久化,並結合加密技術來保護用戶的敏感信息。我們會比較不同的數據持久化選項,並且著重於如何加密數據以增強安全性。
在前端開發中,有多種選擇來存儲數據,常見的包括 localStorage
、sessionStorage
和 cookies
。我們在這裡比較它們的特點:
技術 | 有效範圍 | 持久性 | 容量 | 安全性 |
---|---|---|---|---|
localStorage | 整個應用程序 | 永久存儲,直到被刪除 | 約 5-10 MB | 沒有自動加密,需手動加密 |
sessionStorage | 當前會話 | 在會話結束後清除 | 約 5-10 MB | 沒有自動加密,需手動加密 |
Cookies | 整個應用或特定域 | 可設定過期時間 | 約 4 KB | 可以設置 HttpOnly 和 Secure 標誌 |
sessionStorage
的原因sessionStorage
適合存儲在當前會話期間需要保留的數據,且在用戶關閉瀏覽器後會自動清除。localStorage
小,但對於表單這樣的應用來說已經足夠。CryptoJS
對數據進行加密,從而保護敏感數據。接下來,我們將以 "Let’s Collaborate" 表單為例,展示如何使用 sessionStorage
進行加密和數據持久化。
首先,安裝 CryptoJS
用於加密和解密數據:
npm install crypto-js
為了保護數據,我們將使用一個加密密鑰來加密表單數據。在你的環境變數文件(.env
)中,添加如下密鑰:
REACT_APP_SECRET_KEY=your_secret_key
接下來,我們先初始化表單數據,並填入到useForm
。這裡我們將使用 sessionStorage
來持久化表單數據,確保它在當前瀏覽器會話中保存。
import React, { useState } from 'react';
import { useForm } from 'react-hook-form';
import * as styles from '@/components/Form/ContactForm.module.scss';
import CryptoJS from 'crypto-js';
const ContactForm = () => {
// 初始化表單數據狀態
const [formData, setFormData] = useState({
name: '',
email: '',
serviceItem: '',
projectDetails: ''
});
// 使用 useForm hook 來管理表單
const { register, handleSubmit, formState: { errors }, reset } = useForm({
defaultValues: formData // 使用初始狀態來填充表單
});
return (
<form className={styles.contactForm} onSubmit={handleSubmit(onSubmit)}>
{/* 其他表單項目 */}
</form>
);
};
formData
:使用 useState
初始化表單數據。useForm
:React Hook Form 的 useForm
用於管理表單的輸入和狀態。在頁面加載時,我們需要從 sessionStorage
中檢查是否已經保存了加密的表單數據,並將其解密後填充到表單中。
import { useEffect } from 'react';
// 從環境變數中讀取加密密鑰
const SECRET_KEY = process.env.REACT_APP_SECRET_KEY;
const ContactForm = () => {
// Step 2: 從 sessionStorage 加載加密數據
useEffect(() => {
const savedData = sessionStorage.getItem('contactForm');
if (savedData) {
const bytes = CryptoJS.AES.decrypt(savedData, SECRET_KEY);
const decryptedData = JSON.parse(bytes.toString(CryptoJS.enc.Utf8));
setFormData(decryptedData);
reset(decryptedData); // 重設表單數據
}
}, [reset]);
return (
<form className={styles.contactForm} onSubmit={handleSubmit(onSubmit)}>
{/* 其他表單項目 */}
</form>
);
};
每次當用戶在表單中輸入或修改數據時,我們將這些數據加密並保存到 sessionStorage
中,以便在會話期間持續保存數據。
useEffect(() => {
const encryptedData = CryptoJS.AES.encrypt(JSON.stringify(formData), SECRET_KEY).toString();
sessionStorage.setItem('contactForm', encryptedData);
}, [formData]);
const handleInputChange = (e) => {
const { name, value } = e.target;
setFormData((prevData) => ({
...prevData,
[name]: value,
}));
};
return (
<form className={styles.contactForm} onSubmit={handleSubmit(onSubmit)}>
<div className={styles.formGroup}>
<label htmlFor="name">Name</label>
<input
type="text"
{...register('name', { required: 'Name is required' })}
placeholder="Your Name"
value={formData.name} // 綁定到狀態
onChange={handleInputChange} // 監聽變更
/>
{errors.name && <p className={styles.errorText}>{errors.name.message}</p>}
</div>
<div className={styles.formGroup}>
<label htmlFor="email">Email</label>
<input
type="email"
{...register('email', {
required: 'Email is required',
pattern: {
value: /\S+@\S+\.\S+/,
message: 'Enter a valid email',
},
})}
placeholder="Your Email"
value={formData.email} // 綁定到狀態
onChange={handleInputChange} // 監聽變更
/>
{errors.email && <p className={styles.errorText}>{errors.email.message}</p>}
</div>
<div className={styles.formGroup}>
<label htmlFor="serviceItem">Service Items</label>
<select
{...register('serviceItem', { required: 'Please select a service item' })}
value={formData.serviceItem} // 綁定到狀態
onChange={handleInputChange} // 監聽變更
>
<option value="">Select a service</option>
<option value="design">Design</option>
<option value="development">Development</option>
<option value="consultation">Consultation</option>
</select>
{errors.serviceItem && <p className={styles.errorText}>{errors.serviceItem.message}</p>}
</div>
<div className={styles.formGroup}>
<label htmlFor="projectDetails">Project Details</label>
<textarea
{...register('projectDetails', { required: 'Project details are required' })}
placeholder="Describe your project"
value={formData.projectDetails} // 綁定到狀態
onChange={handleInputChange} // 監聽變更
></textarea>
{errors.projectDetails && <p className={styles.errorText}>{errors.projectDetails.message}</p>}
</div>
{/* 其他表單項目 */}
</form>
);
sessionStorage
在表單提交後,我們會清除 sessionStorage
中的表單數據,避免重複填充舊數據。
const onSubmit = (data) => {
setIsSending(true); // 開始發送,設置 loading 狀態
// EmailJS 發送邏輯
const templateParams = {
from_name: data.name,
from_email: data.email,
service: data.serviceItem,
message: data.projectDetails,
};
emailjs
.send(
process.env.EMAILJS_SERVICE_ID, // 使用環境變數中的 Service ID
process.env.EMAILJS_TEMPLATE_ID, // 使用環境變數中的 Template ID
templateParams,
process.env.EMAILJS_PUBLIC_KEY // 使用環境變數中的 Public Key
)
.then(
(response) => {
console.log('Email sent successfully!', response.status, response.text);
alert('Your message was sent successfully!');
sessionStorage.removeItem('contactForm'); // 提交後清除 sessionStorage
setIsSending(false); // 發送完成,重置 loading 狀態
},
(error) => {
console.log('Failed to send email...', error);
alert('There was an error sending your message.');
setIsSending(false); // 發送失敗,重置 loading 狀態
}
);
};
在這篇文章中,我們學習了如何使用 sessionStorage
來持久化表單數據,並使用加密技術來保護用戶數據的安全性。sessionStorage
適合短期的數據存儲,當瀏覽器關閉後自動清除數據,這使其成為表單和購物車等短期使用數據的理想選擇。
✨ 流光館Luma<∕> ✨ 期待與你繼續探索更多技術知識!